package com.diagrammer.render
{
	import com.diagrammer.event.NodeEvent;
	import com.diagrammer.vo.NodeVO;
	
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	/**
	 * 节点点击事件,event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */
	[Event(name="nodeClick", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 节点点击事件，同时按下ctrl键，event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */
	[Event(name="nodeClickCtrl", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 更新节点关联的线条,event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */	
	[Event(name="updateLines", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 节点开始移动事件,event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */	
	[Event(name="dragMoveStart", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 节点正在移动事件,event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */	
	[Event(name="dragMoving", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 节点停止移动事件,event.data = NodeRender
	 * @eventType com.diagrammer.common.event.NodeEvent
	 */	
	[Event(name="dragMoveStop", type="com.diagrammer.event.NodeEvent")]
	/**
	 * 节点渲染器基类，基于<code>com.diagrammer.render.BaseRender</code><br/>
	 * 节点的点击事件由 mouse_down 和 mouse_up完成，不是添加 mouse_click 事件监听
	 * 
	 * @author Dwei <b>2012-02-13</b>
	 * 
	 */	
	public class NodeRender extends BaseRender
	{
//============================================================================
//parameter
//============================================================================
		/**
		 * 标识vo对象是否改变
		 * @private
		 */		
		private var _voChangedFlag:Boolean;
		
		private var _vo:NodeVO;
		
		private var _dragMovable:Boolean;
//============================================================================
//constructor
//============================================================================
		public function NodeRender()
		{
			super();
			_voChangedFlag = false;
			_dragMovable = true;
		}
//============================================================================
//override
//============================================================================
		override protected function commitProperties():void
		{
			if (_voChangedFlag)
			{
				commitVOProperties();
				_voChangedFlag = false;
				invalidateRender();
			}
			super.commitProperties();
		}
		
		/**
		 * @inheritDoc
		 */		
		override protected function initializeHandlers():void
		{
			super.initializeHandlers();
			addEventListener("xChanged", positionChanged_handler);
			addEventListener("yChanged", positionChanged_handler);
			addEventListener("widthChanged", sizeChanged_handler);
			addEventListener("heightChanged", sizeChanged_handler);
			initializeMouseHandler();
		}
		
		/**
		 * @inheritDoc
		 */		
		override protected function commitFocusProperties():void
		{
			
		}
		
		/**
		 * @inheritDoc
		 */		
		override protected function updateRender(unscaledWidth:Number, unscaledHeight:Number):void
		{
			
		}
//============================================================================
//public
//============================================================================
		/**
		 * 更新该节点关联的线条
		 * 
		 */		
		public function updateLines():void
		{
			dispatchEvent(new NodeEvent(NodeEvent.UPDATE_LINES, this));
		}
//============================================================================
//protected
//============================================================================
		/**
		 * 在当前属性vo对象改变时调用，仅需要更新会影响界面显示效果的相关属性值，不必在该处进行重绘或者其它操作。此方法是一种高级方法，可在创建 NodeRender 的子类时覆盖。<br/>
		 * 您无需直接调用此方法。在设置属性<b>vo</b>的值时，会自动调用该方法。<br/>
		 * 方法执行后会调用 invalidateRender() 方法，根据在该方法中设置的相关属性来更新界面
		 * 
		 */		
		protected function commitVOProperties():void
		{
			
		}
		
		/**
		 * 初始化鼠标事件监听
		 * 
		 */		
		protected function initializeMouseHandler():void
		{
			canvas.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown_handler);
		}
//============================================================================
//handler
//============================================================================
		/**
		 * 记录鼠标按下时，与节点原点的距离
		 * @private
		 */		
		private var distBackup:Point;
		/**
		 * 标识节点是否在移动
		 * @private
		 */		
		private var isMoving:Boolean;
		protected function mouseDown_handler(event:MouseEvent):void
		{
			event.stopPropagation();
			isMoving = false;
			//保存鼠标到节点原点的距离
			distBackup = new Point(mouseX, mouseY);
			//添加全局鼠标事件，开始拖拽移动
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove_stage_handler);
			//添加节点上的鼠标释放事件，并解释为在节点上单击事件
			addEventListener(MouseEvent.MOUSE_UP, mouseUp_handler);
		}
		
		protected function mouseUp_handler(event:MouseEvent):void
		{
			event.stopPropagation();
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove_stage_handler);
			removeEventListener(MouseEvent.MOUSE_UP, mouseUp_handler);
			if (event.ctrlKey)
				dispatchEvent(new NodeEvent(NodeEvent.NODE_CLICK_CTRL, this));
			else
				dispatchEvent(new NodeEvent(NodeEvent.NODE_CLICK, this));
		}
		
		protected function mouseMove_stage_handler(event:MouseEvent):void
		{
			event.stopPropagation();
			if (!isMoving)
			//如果节点不能拖拽，移除舞台上的鼠标移动事件监听，并返回
			if (!dragMovable)
				stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove_stage_handler);
			//节点可以拖动，后台添加鼠标释放事件监听（移除此次拖拽的事件监听）
			if (!isMoving)
			{
				//移除节点上的鼠标释放事件监听（不派发节点的单击事件）
				removeEventListener(MouseEvent.MOUSE_UP, mouseUp_handler);
				if (!dragMovable) return;
				stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp_stage_handler);
				isMoving = true;
				dispatchEvent(new NodeEvent(NodeEvent.DRAGMOVE_START, this));
			}
			//开始移动
			x = parent.mouseX - distBackup.x;
			y = parent.mouseY - distBackup.y;
			//派发节点 DRAGMOVING 事件
			dispatchEvent(new NodeEvent(NodeEvent.DRAGMOVING, this));
		}
		
		protected function mouseUp_stage_handler(event:MouseEvent):void
		{
			event.stopPropagation();
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove_stage_handler);
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp_stage_handler);
			isMoving = false;
			dispatchEvent(new NodeEvent(NodeEvent.DRAGMOVE_STOP, this));
		}
//============================================================================
//private
//============================================================================
		/**
		 * 节点位置改变，更新相关线条
		 * @param event
		 * @private
		 */		
		private function positionChanged_handler(event:Event):void
		{
			event.stopPropagation();
			updateLines();
		}
		
		/**
		 * 节点大小改变，更新相关线条，并更新界面
		 * @param event
		 * @private
		 */		
		private function sizeChanged_handler(event:Event):void
		{
			event.stopPropagation();
			invalidateRender();
			updateLines();
		}
//============================================================================
//getter/setter
//============================================================================

		[Bindable]
		/**
		 * 节点VO对象，不能为null
		 */
		public function get vo():NodeVO
		{
			return _vo;
		}

		/**
		 * @private
		 */
		public function set vo(value:NodeVO):void
		{
			if (value == vo) return;
			if (!value) throw new Error("NodeRender.vo不能为null");
			_vo = value;
			_voChangedFlag = true;
			invalidateProperties();
		}

		/**
		 * 节点是否可以拖拽移动，默认为true
		 */
		public function get dragMovable():Boolean
		{
			return _dragMovable;
		}

		/**
		 * @private
		 */
		public function set dragMovable(value:Boolean):void
		{
			if (value == dragMovable) return;
			_dragMovable = value;
		}


	}
}